package com.link.base.base.user.controller;

import com.link.base.base.enterprise.model.Enterprise;
import com.link.base.base.user.model.User;
import com.link.base.base.enterprise.service.EnterpriseService;
import com.link.base.base.passwdhistory.model.PasswdHistory;
import com.link.base.base.passwdhistory.service.PasswdHistoryService;
import com.link.base.base.user.service.UserService;
import com.link.core.cllog.LCLogger;
import com.link.core.basic.annotations.JsonParam;
import com.link.core.basic.controller.BasicController;
import com.link.core.basic.controller.BasicControllerException;
import com.link.core.basic.interceptor.SecurityInterceptor;
import com.link.core.basic.service.BasicService;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.util.*;
import com.link.core.util.redisclient.LinkRedisClient;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author unknown
 * @date unknown
 * @comments 忘记密码
 */
@Controller
@RequestMapping("/forgotpassword")
public class ForgotPasswordController extends BasicController<User> {
    /** private static final int sendTimesLimit = 3; // 每天每个手机号能发送验证码的次数*/
    /**
     * 每个会话每次发送验证码的时间间隔（秒）
     */
    private static final int SEND_TIME_INTERVAL = 60;

    /**private static final String TempleteCode = "SMS_50065081";// 短信模板代码*/
    /**
     * 每个手机号验证码有效期（秒）
     */
    private static final int VERIFICATION_CODE_TERM = 600;
    /**
     * 验证码保存的唯一性识别key值
     */
    private static final String VERIFICATION_CODE_KEY = "#VerificationCode#ModifyPasswd";
    /**
     * 用户前端输入的验证码，保存的唯一性识别key值
     */
    private static final String USERINPUT_CODE_KEY = "#UserInputCode#ModifyPasswd";
    @Resource
    private UserService userService;
    @Resource
    private EnterpriseService enterpriseService;
    @Resource
    private PasswdHistoryService passwdHistoryService;

    /**
     * 获取service
     */
    @Override
    public BasicService<User> getBasicService() throws Exception {
        if (userService != null) {
            return userService;
        }
        throw new BasicControllerException("获取Basic Service 失败，请确认程序代码是否正确！");
    }

    /**
     * 生成随机验证码
     */
    private String genVCode() {
        Random rd = new Random();
        String vCode = "";
        //验证码长度
        int vCodeNum = 6;
        for (int i = 0; i < vCodeNum; i++) {
            vCode += String.valueOf(rd.nextInt(10));
        }
        return vCode;
    }

    /**
     * 发送短信验证码
     */
    @RequestMapping(value = "/sendSMSCode", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> sendSMSCode(@JsonParam User record, HttpSession session, HttpServletRequest request,
                                           HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>();
        LinkRedisClient jedis = null;
        try {
            // 根据用户名获取该用户信息
            User user = new User();
            user = userService.getUserByUsername(record.getUsername());
            if (null == user) {
                throw new BasicServiceException("用户名不存在");
            }
            if (record.getContactPhone().equals(user.getContactPhone())) {
                // 生成一个验证码
                String vCode = genVCode();

                // 发送短信验证码
                LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
                params.put("no", vCode);
                String vCodeMsgTemplate = PropertyUtil.getCommonProperty(RedisConstants.key_vCodeMsgTemplate);
                result = SendSmsUtil.sendMsg2(user.getContactPhone(), vCodeMsgTemplate, params, null);

                //当获取验证码成功之后，在session中存入当前修改密码对应的用户。
                //当到下一步修改密码的时候，从session中直接获取用户。避免被串改密码
                //HuangLJ 2018年01月19日
//              String token = MySecurityInterceptor.token.get();

                session.setAttribute("modifyPasswdUser", record.getUsername());
                String suc = "success";
                if (!(boolean) result.get(suc)) {
                    return result;
                }
                jedis = RedisUtil.getJedis();
                // 设置redis的唯一性key
                String redisKey = user.getContactPhone() + VERIFICATION_CODE_KEY;
                // 将验证码存入redis
                jedis.set(redisKey, vCode);
                // 设置验证码在redis中的有效时间
                jedis.expire(redisKey, VERIFICATION_CODE_TERM);

                jedis.set("modifypss_" + user.getUsername(), record.getUsername());
                jedis.expire("modifypss_" + user.getUsername(), 600);
                result.put("result", SEND_TIME_INTERVAL);
                //result.put("success", true);
            } else {
                result.put("success", false);
                result.put("result", "该号码与本账户绑定的手机号码不一致");
            }

        } catch (Exception e) {
            LCLogger.withException(e);
            result.put("success", false);
            result.put("result", e.getMessage());
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    /**
     * 当验证码正确跳转到重设密码页面
     */
    @RequestMapping(value = "/confirmCode")
    @ResponseBody
    public Map<String, Object> confirmCode(String verifyCode, String contactPhone,
                                           String username, HttpSession session,
                                           HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>();
        LinkRedisClient jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            // 设置redis中验证码的唯一性key
            String redisKey = contactPhone + VERIFICATION_CODE_KEY;
            // 判断验证码是否能正确
            if (verifyCode.equals(jedis.get(redisKey))) {
                // 存储用户输入的验证码到redis，并设置有效时间
                String userInputCodeKey = contactPhone + USERINPUT_CODE_KEY;
                jedis.set(userInputCodeKey, verifyCode);
                jedis.expire(userInputCodeKey, VERIFICATION_CODE_TERM);
                User user = userService.getUserByUsername(username);
                Enterprise queryEnp = new Enterprise();
                queryEnp.setCode(user.getCorpid());
                queryEnp.setLoginCorpId(user.getCorpid());
                List<Enterprise> enterpriseList = enterpriseService.getEnterpriseByUserCode(queryEnp);
                if (enterpriseList == null || enterpriseList.size() == 0) {
                    throw new BasicServiceException("找不到对应的企业信息");
                } else if (enterpriseList.size() > 1) {
                    throw new BasicServiceException("找到多个企业信息");
                }
                Enterprise enterprise = enterpriseList.get(0);
                enterprise.setAnonymousFlag("Y");
                //處理數據 只傳輸密碼校驗相關到前台
                Enterprise entity = new Enterprise();
                entity.setAnonymousFlag("Y");
                entity.setPwMinLen(enterprise.getPwMinLen());
                entity.setPwCheckGrade(enterprise.getPwCheckGrade());
                entity.setPwGrade(enterprise.getPwGrade());
                entity.setPwKeepDate(enterprise.getPwKeepDate());
                entity.setForceHistyPw(enterprise.getForceHistyPw());

                result.put("success", true);
                result.put("result", entity);
            } else {
                result.put("result", "验证码错误");
                result.put("success", false);
            }

        } catch (Exception e) {
            LCLogger.withException(e);
            result.put("success", false);
            result.put("result", e.getMessage());
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    /**
     * 重置密码
     */
    @RequestMapping(value = "/modifyPasswd")
    @ResponseBody
    public Map<String, Object> modifyPasswd(String username, String password, HttpSession session,
                                            HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>();
        LinkRedisClient jedis = null;
        try {
            // 根据用户名获取该用户信息
            jedis = RedisUtil.getJedis();
            String userStr = jedis.get("modifypss_" + username);
            User user = userService.getUserByUsername(userStr);
            //把用户信息放到线程中去，确保后续不会报错。
            if (user == null) {
                throw new Exception("修改密码：用户为空！");
            }
            // 校验redis中用户输入的验证码是否正确
            String userInputCode = jedis.get(user.getContactPhone() + USERINPUT_CODE_KEY);
            String verificationCode = jedis.get(user.getContactPhone() + VERIFICATION_CODE_KEY);
            if (StringUtils.isBlank(userInputCode) || !userInputCode.equals(verificationCode)) {
                throw new Exception("验证码过期或者错误，请返回上一步重新获取");
            }
            SecurityInterceptor.tempUser.set(user);
            User userpswd = userService.getUserByUserId(user);
            //对密码进行加密
            // 校验密码
            // 校验历史密码
            Enterprise enterpriseQuery = new Enterprise();
            enterpriseQuery.setCode(userpswd.getCorpid());
            enterpriseQuery.setLoginCorpId(userpswd.getCorpid());
            enterpriseQuery.setPageFlag(false);
            enterpriseQuery.setTotalFlag(true);
            List<Enterprise> enterpriseList = enterpriseService.queryByExamplePage(enterpriseQuery);

            if (enterpriseList == null || enterpriseList.size() < 1) {
                throw new BasicControllerException("没有查询到企业信息！");
            }
            if (enterpriseList.size() > 1) {
                throw new BasicControllerException("根据【" + userpswd.getCorpid() + "】查询到多条企业信息！");
            }
            Enterprise enterprise = enterpriseList.get(0);
            String flag = "Y";
            if (flag.equals(enterprise.getForceHistyPw())) {
                // 如果强制历史密码为Y，则校验是否存在历史密码
                int hisNum = enterprise.getPwKeepDate();

                boolean passwdSameFlag = passwdHistoryService.checkHistory(password, hisNum,
                        userpswd.getUsername());
                String refuse = "refuse";
                if (!passwdSameFlag && refuse.equals(enterprise.getPwCheckGrade())) {
                    throw new BasicServiceException("新密码不能与历史密码一致");
                }
            }
            PasswordUtil.checkPasswd(password, enterprise, user);

            user.setPassword(PasswordUtil.generatePwd(password));
            userService.updatePassword(user);
            //清空该用户密码错误次数
            setLoginErrorTimes(user.getUsername(), 0);

            //把修改的记录写入历史表
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = new Date();
            String changePwDate = sdf.format(date);
            PasswdHistory passwdHistory = new PasswdHistory();
            passwdHistory.setPassword(PasswordUtil.generatePwd(password));
            passwdHistory.setUserName(user.getUsername());
            passwdHistory.setModifyDateTime(changePwDate);
            passwdHistory.setCorpid(user.getCorpid());
            passwdHistoryService.insert(passwdHistory);
            result.put("success", true);
        } catch (Exception e) {
            LCLogger.withException(e);
            result.put("success", false);
            result.put("result", e.getMessage());
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    private static void setLoginErrorTimes(String username, int errorTimes) {
        LinkRedisClient jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            String redisKey = "crm_loginError_info";
            String currentdate = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
            if (jedis.exists(redisKey) && jedis.hmget(redisKey, username).size() > 0) {
                Map<String, String> map = new HashMap<String, String>();
                map.put(username, errorTimes + "+" + currentdate);
                jedis.hdel(redisKey, username);
                jedis.hmset(redisKey, map);
            }
        } finally {
            RedisUtil.returnResource(jedis);
        }
    }

    /***
     * DESC: 密码校验
     *
     * @param user 用户信息
     * @author: xubowen
     * @date: 2019-05-05
     */
    @RequestMapping(value = "/checkOldPassword", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> checkOldPassword(@RequestBody User user, HttpSession session, HttpServletRequest request,
                                                HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>();
        LinkRedisClient jedis = null;

        try {
            //传password会被过滤为null，用attr1暂存
            String password = user.getAttr1();
            String username = user.getUsername().toUpperCase();
            User u = new User();
            u.setUsername(username);
            User rs = userService.queryByLogin(u);

            if (rs == null) {
                result.put("success", false);
                result.put("result", "客户不存在");
                return result;
            }

            jedis = RedisUtil.getJedis();

            jedis.set("modifypss_" + user.getUsername(), username);
            jedis.expire("modifypss_" + username, 600);

            String oldPassword = PasswordUtil.generatePwd(password);
            String truePassword = rs.getPassword();
            //校验原密码是否正确
            userService.checkLoginErrorTimes(username);
            if (!StringUtils.equals(oldPassword, truePassword)) {
                userService.setLoginErrorTimes(username, userService.getLoginErrorTimes(username) + 1);
                throw new BasicServiceException("原密码错误");
            }

            Enterprise queryEnp = new Enterprise();
            queryEnp.setCode(rs.getCorpid());
            queryEnp.setLoginCorpId(rs.getCorpid());
            List<Enterprise> enterpriseList = enterpriseService.getEnterpriseByUserCode(queryEnp);
            if (enterpriseList == null || enterpriseList.size() == 0) {
                throw new BasicServiceException("找不到对应的企业信息");
            } else if (enterpriseList.size() > 1) {
                throw new BasicServiceException("找到多个企业信息");
            }
            Enterprise enterprise = enterpriseList.get(0);
            enterprise.setAnonymousFlag("Y");
            //处理数据，只传送密码校验相关到前台
            Enterprise entity = new Enterprise();
            entity.setAnonymousFlag("Y");
            entity.setPwMinLen(enterprise.getPwMinLen());
            entity.setPwCheckGrade(enterprise.getPwCheckGrade());
            entity.setPwGrade(enterprise.getPwGrade());
            entity.setPwKeepDate(enterprise.getPwKeepDate());
            entity.setForceHistyPw(enterprise.getForceHistyPw());
            entity.setMobileVerifyFlag(enterprise.getMobileVerifyFlag());

            result.put("success", true);
            result.put("result", entity);

        } catch (Exception e) {
            LCLogger.withException(e);
            result.put("success", false);
            result.put("result", e.getMessage());
        }
        return result;
    }


    /***
     * DESC: 校验历史密码
     * @author: xubowen
     * @param username 用户名
     * @param password 密码
     * @date: 2019-05-22
     */
    @RequestMapping(value = "/checkPasswordHistory", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> checkPasswordHistory(String username, String password, HttpSession session, HttpServletRequest request,
                                                    HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>();
        // 校验历史密码
        try {
            User userpswd = userService.getUserByUsername(username);
            Enterprise enterpriseQuery = new Enterprise();
            enterpriseQuery.setCode(userpswd.getCorpid());
            enterpriseQuery.setLoginCorpId(userpswd.getCorpid());
            enterpriseQuery.setPageFlag(false);
            enterpriseQuery.setTotalFlag(true);
            List<Enterprise> enterpriseList = enterpriseService.queryByExamplePage(enterpriseQuery);

            if (enterpriseList == null || enterpriseList.size() < 1) {
                throw new BasicControllerException("没有查询到企业信息！");
            }
            if (enterpriseList.size() > 1) {
                throw new BasicControllerException("根据【" + userpswd.getCorpid() + "】查询到多条企业信息！");
            }
            Enterprise enterprise = enterpriseList.get(0);
            // 如果强制历史密码为Y，则校验是否存在历史密码
            int hisNum = enterprise.getPwKeepDate();
            boolean passwdSameFlag = passwdHistoryService.checkHistory(password, hisNum,
                    userpswd.getUsername());
            if (!passwdSameFlag) {
                result.put("result", "新密码不能与历史密码一致");
            }
            result.put("success", true);
        } catch (Exception e) {
            LCLogger.withException(e);
            result.put("success", false);
            result.put("result", e.getMessage());
        }

        return result;
    }
}
